#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>

// -------------------- 外观模式实现 --------------------

// 子系统1：订单处理系统
class OrderProcessingSystem {
public:
    void processOrder(const std::string& orderDetails) {
        std::cout << "OrderProcessingSystem: Processing order - " << orderDetails << std::endl;
    }
};

// 子系统2：库存管理系统
class InventoryManagementSystem {
public:
    bool checkInventory(const std::string& item) {
        // 示例简化处理，假设所有物品都有库存
        std::cout << "InventoryManagementSystem: Checking inventory for item - " << item << std::endl;
        return true;
    }
};

// 子系统3：用户验证系统
class UserAuthenticationSystem {
public:
    bool authenticateUser(const std::string& userID) {
        // 示例简化处理，假设用户总是验证成功
        std::cout << "UserAuthenticationSystem: Authenticating user - " << userID << std::endl;
        return true;
    }
};

// 外观类：电子商务平台外观
class ECommerceFacade {
    OrderProcessingSystem orderProcessor;
    InventoryManagementSystem inventoryManager;
    UserAuthenticationSystem userAuthenticator;

public:
    void placeOrder(const std::string& userID, const std::string& item, const std::string& orderDetails) {
        std::cout << "\nECommerceFacade: Initiating order placement...\n";
        if (userAuthenticator.authenticateUser(userID)) {
            if (inventoryManager.checkInventory(item)) {
                orderProcessor.processOrder(orderDetails);
                std::cout << "ECommerceFacade: Order placed successfully!\n";
            } else {
                std::cout << "ECommerceFacade: Failed to place order - Item out of stock.\n";
            }
        } else {
            std::cout << "ECommerceFacade: Failed to place order - User authentication failed.\n";
        }
    }
};

// -------------------- 享元模式实现 --------------------

// 享元类：用户偏好
class UserPreference {
    std::string preferenceDetails;
public:
    UserPreference(const std::string& details) : preferenceDetails(details) {
        std::cout << "UserPreference: Created preference - " << preferenceDetails << std::endl;
    }

    void display() const {
        std::cout << "UserPreference: " << preferenceDetails << std::endl;
    }
};

// 享元工厂：管理用户偏好的共享
class PreferenceFactory {
    std::unordered_map<std::string, std::shared_ptr<UserPreference>> preferences;
public:
    std::shared_ptr<UserPreference> getPreference(const std::string& preferenceDetails) {
        auto it = preferences.find(preferenceDetails);
        if (it != preferences.end()) {
            std::cout << "PreferenceFactory: Reusing existing preference - " << preferenceDetails << std::endl;
            return it->second;
        } else {
            std::cout << "PreferenceFactory: Creating new preference - " << preferenceDetails << std::endl;
            auto pref = std::make_shared<UserPreference>(preferenceDetails);
            preferences[preferenceDetails] = pref;
            return pref;
        }
    }
};

// -------------------- 测试用例 --------------------

int main() {
    // -------------------- 测试外观模式 --------------------
    std::cout << "===== 外观模式测试 =====\n";
    ECommerceFacade ecommerce;

    // 客户端通过外观接口下订单
    ecommerce.placeOrder("User123", "Laptop", "Order#001: Laptop x1");
    ecommerce.placeOrder("User456", "Smartphone", "Order#002: Smartphone x2");

    // -------------------- 测试享元模式 --------------------
    std::cout << "\n===== 享元模式测试 =====\n";
    PreferenceFactory prefFactory;

    // 模拟多个用户会话共享用户偏好
    std::vector<std::shared_ptr<UserPreference>> userPreferences;

    // 用户A和用户B具有相同的偏好
    userPreferences.push_back(prefFactory.getPreference("Dark Mode"));
    userPreferences.push_back(prefFactory.getPreference("Dark Mode"));

    // 用户C具有不同的偏好
    userPreferences.push_back(prefFactory.getPreference("Light Mode"));

    // 用户D又具有相同的偏好
    userPreferences.push_back(prefFactory.getPreference("Dark Mode"));

    // 显示所有用户的偏好
    std::cout << "\nDisplaying User Preferences:\n";
    for (size_t i = 0; i < userPreferences.size(); ++i) {
        std::cout << "User " << i + 1 << ": ";
        userPreferences[i]->display();
    }

    return 0;
}
